﻿using System;
using System.Collections;
using System.Reflection;

namespace CodeLibrary.Reflection.Delegate
{
    public static class GetterSetterFactory
    {
        private static readonly Hashtable s_getterDict = Hashtable.Synchronized(new Hashtable());
        private static readonly Hashtable s_setterDict = Hashtable.Synchronized(new Hashtable());

        public static ISetValue CreatePropertySetterWrapper(PropertyInfo propertyInfo)
        {
            if (propertyInfo == null)
                throw new ArgumentNullException("propertyInfo");
            if (propertyInfo.CanWrite == false)
                throw new NotSupportedException("属性不支持写操作。");

            MethodInfo mi = propertyInfo.GetSetMethod(true);

            if (mi.GetParameters().Length > 1)
                throw new NotSupportedException("不支持构造索引器属性的委托。");

            if (mi.IsStatic)
            {
                Type instanceType = typeof(StaticSetterWrapper<>).MakeGenericType(propertyInfo.PropertyType);
                return (ISetValue)Activator.CreateInstance(instanceType, propertyInfo);
            }
            else
            {
                Type instanceType = typeof(SetterWrapper<,>).MakeGenericType(propertyInfo.DeclaringType, propertyInfo.PropertyType);
                return (ISetValue)Activator.CreateInstance(instanceType, propertyInfo);
            }

        }

        public static IGetValue CreatePropertyGetterWrapper(PropertyInfo propertyInfo)
        {
            if (propertyInfo == null)
                throw new ArgumentNullException("propertyInfo");
            if (propertyInfo.CanRead == false)
                throw new InvalidOperationException("属性不支持读操作。");

            MethodInfo mi = propertyInfo.GetGetMethod(true);

            if (mi.GetParameters().Length > 0)
                throw new NotSupportedException("不支持构造索引器属性的委托。");

            if (mi.IsStatic)
            {
                Type instanceType = typeof(StaticSetterWrapper<>).MakeGenericType(propertyInfo.PropertyType);
                return (IGetValue)Activator.CreateInstance(instanceType, propertyInfo);
            }
            else
            {
                Type instanceType = typeof(GetterWrapper<,>).MakeGenericType(propertyInfo.DeclaringType, propertyInfo.PropertyType);
                return (IGetValue)Activator.CreateInstance(instanceType, propertyInfo);
            }
        }



        internal static IGetValue GetPropertyGetterWrapper(PropertyInfo propertyInfo)
        {
            IGetValue property = (IGetValue)s_getterDict[propertyInfo];
            if (property == null)
            {
                property = CreatePropertyGetterWrapper(propertyInfo);
                s_getterDict.Add(propertyInfo, property);
            }
            return property;
        }

        internal static ISetValue GetPropertySetterWrapper(PropertyInfo propertyInfo)
        {
            ISetValue property = (ISetValue)s_setterDict[propertyInfo];
            if (property == null)
            {
                property = CreatePropertySetterWrapper(propertyInfo);
                s_setterDict.Add(propertyInfo, property);
            }
            return property;
        }

    }
}
